#pragma once

#include <cstdint>

namespace D3D10Utils
{
	class Timer
	{
	public:
		Timer();

		__forceinline float getInGameTime() const; // in seconds
		__forceinline float getDeltaTime() const; // in seconds
		
        // Call before message loop.
		void reset(); 

        // Call when unpaused.
		void start(); 

        // Call when paused.
		void stop();  

        // Call every frame.
		void tick();  

	private:
        uint64_t mLastStartTime;
		uint64_t mInPauseTime;
		uint64_t mLastStopTime;
		uint64_t mPreviousTickTime;
		uint64_t mCurrentTickTime;

		double mSecondsPerCount;
		double mDeltaTime;

		bool mIsStopped;
	};

	// Returns the total time elapsed since reset() was called, NOT counting any
	// time when the clock is stopped.
	float Timer::getInGameTime() const
	{
		// IF we are stopped, do not count the time that has passed since we stopped.
		//
		// ----*---------------*------------------------------*------> time
		// mLastStartTime  mLastStopTime                mCurrentTickTime
		//
		// ELSE:
		// The distance mCurrentTickTime - mLastStartTime includes paused time,
		// which we do not want to count. To correct this, we can subtract 
		// the paused time from mCurrentTickTime:  
		//
		//  (mCurrentTickTime - mInPauseTime) - mLastStartTime 
		//
		//                     |<---mInPauseTime-->|
		// ----*---------------*-------------------*-------------*------> time
		//  mLastStartTime  mLastStopTime       newStartTime  mCurrentTickTime
			
		return (mIsStopped) ? static_cast<float> ( (mLastStopTime - mLastStartTime) * mSecondsPerCount )
			: static_cast<float> ( (mCurrentTickTime - mInPauseTime - mLastStartTime) * mSecondsPerCount );
	}

	float Timer::getDeltaTime() const
	{
		return static_cast<float> (mDeltaTime);
	}
}

